package com.mtask.task.service.impl;


import com.mtask.common.constants.TaskStatus;
import com.mtask.common.entity.task.CallbackJob;
import com.mtask.common.entity.task.EmailJob;
import com.mtask.common.entity.task.NotifyJob;
import com.mtask.common.entity.task.TaskJob;
import com.mtask.task.core.CronScheduler;
import com.mtask.task.repository.CallbackJobRepository;
import com.mtask.task.repository.EmailJobRepository;
import com.mtask.task.repository.JobRepository;
import com.mtask.task.repository.NotifyJobRepository;
import com.mtask.task.service.TaskService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class TaskServiceImpl implements TaskService {
    @Resource
    private JobRepository jobRepository;

    @Resource
    private CallbackJobRepository callbackJobRepository;

    @Resource
    private EmailJobRepository emailJobRepository;
    @Resource
    private NotifyJobRepository notifyJobRepository;
    @Resource
    private CronScheduler cronScheduler;

    private List<Object> findReferenceJob(List<TaskJob> tasks) {
        List<Object> jobs = new ArrayList<>();
        for (TaskJob task : tasks) {
            String referenceType = task.getReferenceType();
            if (referenceType.equals("email")) {
                Optional<EmailJob> byId = emailJobRepository.findById(task.getReferenceId());
                if (byId.isPresent()) {
                    jobs.add(byId.get());
                } else {
                    jobs.add(null);
                }
            } else if (referenceType.equals("callback")) {
                Optional<CallbackJob> byId = callbackJobRepository.findById(task.getReferenceId());
                if (byId.isPresent()) {
                    jobs.add(byId.get());
                } else {
                    jobs.add(null);
                }
            } else if (referenceType.equals("notify")) {
                Optional<NotifyJob> byId = notifyJobRepository.findById(task.getReferenceId());
                if (byId.isPresent()) {
                    jobs.add(byId.get());
                } else {
                    jobs.add(null);
                }
            }
        }
        return jobs;
    }

    @Override
    public List<TaskJob> startJobWithDb() {
        List<TaskJob> tasks = jobRepository.findAll();
        cronScheduler.addAllTaskJob(tasks, findReferenceJob(tasks));
        return tasks;
    }

    @Override
    public List<TaskJob> startAllJobWithDb() {
        List<TaskJob> tasks = jobRepository.findAll();
        tasks.forEach(taskJob -> taskJob.setStatus(TaskStatus.start));
        cronScheduler.addAllTaskJob(tasks, findReferenceJob(tasks));
        jobRepository.saveAll(tasks);
        return tasks;
    }

    @Override
    public boolean startJob(Integer id) {
        Optional<TaskJob> jobOptional = jobRepository.findById(id);
        if (jobOptional.isPresent()) {
            TaskJob taskJob = jobOptional.get();
            cronScheduler.resumeTaskJob(taskJob);
            taskJob.setStatus(TaskStatus.start);
            jobRepository.save(taskJob);
            return true;
        }
        return false;
    }

    @Override
    public boolean stopJob(Integer id) {
        Optional<TaskJob> jobOptional = jobRepository.findById(id);
        if (jobOptional.isPresent()) {
            TaskJob taskJob = jobOptional.get();
            cronScheduler.stopTaskJob(taskJob);
            taskJob.setStatus(TaskStatus.stop);
            jobRepository.save(taskJob);
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteJob(Integer id) {
        return false;
    }

    @Override
    public TaskJob createJob(TaskJob job) {
        return null;
    }


    @Override
    public List<TaskJob> deleteAllJobWithDb() {
        List<TaskJob> jobs = jobRepository.findAll();
        cronScheduler.deleteAllTaskJob(jobs);
        jobs.forEach(job -> job.setStatus(TaskStatus.stop));
        jobRepository.saveAll(jobs);
        return jobs;
    }
}

